package com.lmt.service.impl;

import com.lmt.base.BaseService;
import com.lmt.base.ResultData;
import com.lmt.entity.LoginLog;
import com.lmt.entity.UserInfo;
import com.lmt.entity.search.UserInfoSearch;
import com.lmt.repository.UserInfoRepository;
import com.lmt.service.*;
import com.lmt.util.AesPasswordUtil;
import com.lmt.util.RedisCacheUtil;
import com.lmt.util.ResultUtil;
import com.lmt.util.SystemConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * Date 2018/07/17
 *
 * @author MT-Lin
 */
@Service("UserInfoServiceImpl")
public class UserInfoServiceImpl extends BaseService implements UserInfoService {

	private Logger logger = LoggerFactory.getLogger(UserInfoServiceImpl.class);

	private final UserInfoRepository userInfoRepository;

	private final LoginLogService loginLogService;

	private final CollectionService collectionService;

	private final ResourceTempService resourceTempService;

	private final ResourceDownloadService resourceDownloadService;

	private final RedisCacheUtil redisCacheUtil;

	@Autowired
	public UserInfoServiceImpl(UserInfoRepository userInfoRepository, LoginLogService loginLogService, CollectionService collectionService, ResourceTempService resourceTempService, ResourceDownloadService resourceDownloadService, RedisCacheUtil redisCacheUtil) {
		this.userInfoRepository = userInfoRepository;
		this.loginLogService = loginLogService;
		this.collectionService = collectionService;
		this.resourceTempService = resourceTempService;
		this.resourceDownloadService = resourceDownloadService;
		this.redisCacheUtil = redisCacheUtil;
	}

	@Override
	public ResultData save(UserInfo userInfo) throws Exception {
		String newPassword = AesPasswordUtil.encrypt(userInfo.getUserPassword());
		String userType = SystemConstant.USER_TYPE_ADMIN_CODE.equals(userInfo.getUserType()) ? "管理员" : "用户";
		userInfo.setUserPassword(newPassword);
		userInfo.setPasswordErrorTime(SystemConstant.DEFAULT_PASSWORD_ERROR_TIME);
		userInfo.setStatus(SystemConstant.COUNT_UNFREEZE_CODE);
		UserInfo exitUser = this.userInfoRepository.findByUserName(userInfo.getUserName());
		if (null != exitUser) {
			return ResultUtil.newFail("该用户名已存在");
		}
		this.userInfoRepository.save(userInfo);
		if (null == userInfo.getId()) {
			return ResultUtil.newFail(userType + "注册失败");
		}
		return ResultUtil.newSuccess(userType + "注册成功");
	}

	@Override
	public ResultData login(UserInfo userInfo, HttpSession session) throws Exception {
		UserInfo loginUser = this.userInfoRepository.findByUserName(userInfo.getUserName());
		if (null != loginUser) {
			LoginLog loginLog = new LoginLog();
			loginLog.setUserId(loginUser.getId());
			loginLog.setStatus(loginUser.getStatus());
			loginLog.setPasswordErrorTime(loginUser.getPasswordErrorTime());
			// 在判断密码前应该先判断该用户的密码错误次数是否可以冻结用户，密码错误出错5次或者被管理员冻结
			if (loginUser.getPasswordErrorTime() >= SystemConstant.PASSWORD_ERROR_TIME
					|| SystemConstant.COUNT_FREEZE_CODE.equals(loginUser.getStatus())) {
				loginLog.setResult(SystemConstant.LOGIN_FAIL);
				this.loginLogService.save(loginLog);
				return ResultUtil.newFail("该帐号已被冻结");
			}
			String newPassword = AesPasswordUtil.encrypt(userInfo.getUserPassword());
			if (newPassword.equals(loginUser.getUserPassword())) {
				// 登陆成功，将用户信息包括tokenId和sessionId缓存到Redis
				UUID uuid = UUID.randomUUID();
				String tokenId = uuid.toString();
				loginUser.setTokenId(tokenId);
				loginUser.setSessionId(session.getId());
				redisCacheUtil.cacheUserInfo(loginUser);
				// 将密码错误次数改成默认值
				if (loginUser.getPasswordErrorTime() != SystemConstant.DEFAULT_PASSWORD_ERROR_TIME) {
					loginUser.setPasswordErrorTime(SystemConstant.DEFAULT_PASSWORD_ERROR_TIME);
					this.userInfoRepository.save(loginUser);
				}
				loginLog.setResult(SystemConstant.LOGIN_SUCCESS);
				this.loginLogService.save(loginLog);
				logger.info("用户名：{} ID：{} 登录成功", loginUser.getUserName(), loginUser.getId());
				Map<String, String> result = new HashMap<>();
				result.put(SystemConstant.USER_TYPE, loginUser.getUserType());
				result.put(SystemConstant.USER_LOGIN_EVIDENCE, loginUser.getTokenId());
				return ResultUtil.newSuccess("登录成功", result);
			}
			// 密码错误，更新该帐号的密码错误次数
			loginUser.setPasswordErrorTime(loginUser.getPasswordErrorTime() + 1);
			loginLog.setPasswordErrorTime(loginUser.getPasswordErrorTime());
			loginLog.setResult(SystemConstant.LOGIN_FAIL);
			this.userInfoRepository.save(loginUser);
			if (loginUser.getPasswordErrorTime() >= SystemConstant.PASSWORD_ERROR_TIME) {
				loginUser.setStatus(SystemConstant.COUNT_FREEZE_CODE);
				loginLog.setStatus(loginUser.getStatus());
				this.loginLogService.save(loginLog);
				this.userInfoRepository.save(loginUser);
				return ResultUtil.newFail("密码错误次数达到 5 次，该帐号已被冻结，请联系管理员解冻！");
			}
			this.loginLogService.save(loginLog);
		}
		return ResultUtil.newFail("密码或用户名错误");
	}

	@Override
	public ResultData search(UserInfoSearch userInfoSearch) {
		StringBuffer sql = new StringBuffer();
		sql.append("SELECT ui.id, ui.description, ui.email, ");
		sql.append("DATE_FORMAT(ui.birthday, '%Y-%m-%d') AS birthday, " );
		sql.append("ui.address_code AS addressCode, ");
		sql.append("ui.user_name AS userName, ");
		sql.append("ui.gmt_create AS registerTime, ");
		sql.append("ui.phone_number AS phoneNumber, ");
		sql.append("(SELECT dd.designation FROM digital_dictionary AS dd WHERE dd.code = ui.profession) ");
		sql.append("AS profession, ");
		sql.append("(SELECT dd.designation FROM digital_dictionary AS dd WHERE dd.code = ui.sex) ");
		sql.append("AS sex, ");
		sql.append("(SELECT dd.designation FROM digital_dictionary AS dd WHERE dd.code = ui.user_type) ");
		sql.append("AS userType, ");
		sql.append("(SELECT dd.designation FROM digital_dictionary AS dd WHERE dd.code = ui.status) ");
		sql.append("AS status ");
		sql.append("FROM user_info AS ui WHERE 1=1 ");
		if (!StringUtils.isEmpty(userInfoSearch.getKeyword())) {
			sql.append("AND (ui.user_name LIKE ? OR ui.description LIKE ?) ");
			userInfoSearch.setParamsCount(2);
		}
		Map searchResult = this.paginationSearch(sql, userInfoSearch);
		return ResultUtil.newSuccess("查询成功", searchResult);
	}

	@Override
	public ResultData delete(List<UserInfo> userInfoList) {
		for (UserInfo userInfo : userInfoList) {
			this.userInfoRepository.deleteById(userInfo.getId());
		}
		return ResultUtil.newSuccess("删除成功");
	}

	@Override
	public ResultData freeze(List<UserInfo> userInfoList) {
		UserInfo userInfoFreeze;
		for (UserInfo userInfo : userInfoList) {
			userInfoFreeze = this.userInfoRepository.findById(userInfo.getId()).orElse(null);
			if (null == userInfoFreeze) {
				return ResultUtil.newFail("冻结的账号不存在, ID:" + userInfo.getId());
			}
			userInfoFreeze.setStatus(SystemConstant.COUNT_FREEZE_CODE);
			this.userInfoRepository.save(userInfoFreeze);
		}
		return ResultUtil.newSuccess("冻结成功");
	}

	@Override
	public ResultData unfreeze(List<UserInfo> userInfoList) {
		UserInfo userInfoUnfreeze;
		for (UserInfo userInfo : userInfoList) {
			userInfoUnfreeze = this.userInfoRepository.findById(userInfo.getId()).orElse(null);
			if (null == userInfoUnfreeze) {
				return ResultUtil.newFail("解冻账号不存在，ID：" + userInfo.getId());
			}
			userInfoUnfreeze.setStatus(SystemConstant.COUNT_UNFREEZE_CODE);
			userInfoUnfreeze.setPasswordErrorTime(SystemConstant.DEFAULT_PASSWORD_ERROR_TIME);
			this.userInfoRepository.save(userInfoUnfreeze);
		}
		return ResultUtil.newSuccess("解冻成功");
	}

	@Override
	public ResultData resetPassword(List<UserInfo> userInfoList) throws Exception {
		UserInfo userInfoResetPassword;
		String newPassword = AesPasswordUtil.encrypt(SystemConstant.DEFAULT_PASSWORD);
		for (UserInfo userInfo : userInfoList) {
			userInfoResetPassword = this.userInfoRepository.findById(userInfo.getId()).orElse(null);
			if (null == userInfoResetPassword) {
				return ResultUtil.newFail("重置密码的账号不存在，ID：" + userInfo.getId());
			}
			userInfoResetPassword.setUserPassword(newPassword);
			userInfoResetPassword.setPasswordErrorTime(SystemConstant.DEFAULT_PASSWORD_ERROR_TIME);
			userInfoResetPassword.setStatus(SystemConstant.COUNT_UNFREEZE_CODE);
			this.userInfoRepository.save(userInfoResetPassword);
		}
		return ResultUtil.newSuccess("密码重置成功");
	}

	@Override
	public String getUserNameById(String id) {
		UserInfo userInfo = this.userInfoRepository.findById(id).orElse(null);
		if (null == userInfo) {
			return null;
		}
		return userInfo.getUserName();
	}

	@Override
	public ResultData getUserInfo(String tokenId) {
		UserInfo userInfo = this.redisCacheUtil.getUserInfoFromCache(tokenId);
		Map<String, Object> result = new HashMap<>(3);
		result.put("userName", userInfo.getUserName());
		result.put("uploadNum", this.resourceTempService.getUploadNum(userInfo.getId()));
		result.put("downloadNum", this.resourceDownloadService.getDownloadNum(userInfo.getId()));
		result.put("collectNum", this.collectionService.getCollectNum(userInfo.getId()));
		return ResultUtil.newSuccess("用户信息获取成功", result);
	}
}
